/*
* File: ContactManager.java
* Written by Kyle McCready, Viet Le, and David Hudson
* Started April 11, 2012
* Stored at http://code.google.com/p/sa-con-man/ on Google code
* 
* This program was written as the final project for CSE489 - Zero Defect 
* Software Design Spring 2012. It follows the specification submitted on 
* April 11 2012, which can be viewed online at: http://goo.gl/MH0Ol
* 
* This file is the main application, which works in conjunction with the 
* following files:
* ContactFileEncryptor.java
* ContactXMLParser.java
* ContactXMLWriter.java
*/
package contactmanager;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;

class NameObject
{
    /*
    * --Constants--
    * firstName    := A first name of a contact entry
    * middleName   := A middle name of a contact entry
    * sirName      := A sir name of a contact entry
    * nickName     := A nick name of a contact entry
    * primaryName  := Boolean indicating if this is the primary NameObject for the contact
    */
    String firstName;
    String middleName;
    String sirName;
    String nickName;
    boolean primaryName;
}

class PhoneObject
{
    /*
    * --Constants--
    * areaCode     := An area code of a phone number for a contact entry
    * localNumber  := A local number of a phone number for a contact entry
    * primaryPhone := Boolean indicating if this is the primary PhoneObject for the contact
    */
    String areaCode;
    String localNumber;
    boolean primaryPhone;
}

class AddressObject
{
    /*
    * --Constants--
    * state        := A state attribute of a contact's address entry
    * city         := A city attribute of a contact's address entry
    * zipCode      := A zip code attribute of a contact's address entry
    * streetAddress:= A street address attribute of a contact's address entry
    * primaryAddress:= Boolean indicating if this is the primary AddressObject for the contact
    */
    String state;
    String city;
    String zipCode;
    String streetAddress;
    boolean primaryAddress;
}

class EmailObject
{
    /*
    * --Constants--
    * emailAddress     := An email address of a EmailObject for a contact entry
    * primaryEmail     := Boolean indicating if this is the primary EmailObject for the contact
    */
    String emailAddress;
    boolean primaryEmail;
}

class IMObject
{
    /*
    * --Constants--
    * provider     := The provider of the IM service used in this IMObject for a contact entry
    * userName     := The username used in this IMObject for a contact entry
    * primaryIM    := Boolean indicating if this is the primary IMObject for the contact
    */
    String provider;
    String userName;
    boolean primaryIM;
}

class ContactObject
{
    /*
    * --Constants--
    * name         := Array list of all NameObjects linked to this specific contact
    * phoneNumber  := Array list of all PhoneObjects linked to this specific contact
    * address      := Array list of all AddressObjects linked to this specific contact
    * email        := Array list of all EmailObjects linked to this specific contact
    * im           := Array list of all IMObjects linked to this specific contact
    * birthday     := String containing the birthday of the contact
    */
    
    //This class contains an aggrigation of all elements belonging to 
    //a single contact entry.
    private ArrayList<NameObject> name = new ArrayList();
    private ArrayList<PhoneObject> phoneNumber = new ArrayList();
    private ArrayList<AddressObject> address = new ArrayList();
    private ArrayList<EmailObject> email = new ArrayList();
    private ArrayList<IMObject> im = new ArrayList();
    private String Birthday = "";
    
    //adders
    public void addName(NameObject newName)
    {
        /*
        * name := name + newName
        */
        name.add(newName);
    }
    public void addPhoneNumber(PhoneObject newPhone)
    {
        /*
        * phoneNumber := phoneNumber + newPhone
        */
        phoneNumber.add(newPhone);
    }
    public void addAddress(AddressObject newAddress)
    {
        /*
        * address := address + newAddress
        */
        address.add(newAddress);
    }
    public void addEmail(EmailObject newEmail)
    {
        /*
        * email := email + newEmail
        */
        email.add(newEmail);
    }
    public void addIM(IMObject newIM)
    {
        /*
        * im := im + newIM
        */
        im.add(newIM);
    }
    
    //birthday getter setter
    public void setBirthday(String birthday)
    {
        /*
        * Birthday := birthday
        */
        Birthday = birthday;
    }
    
    public String getBirthday()
    {
        /*
        * returns Birthday 
        */
        return(Birthday);
    }
    
    //removers
    public void rmName(int index)
    {
        /*
        * name := name - name[index]
        */
        name.remove(index);
    }
    public void rmPhoneNumber(int index)
    {
        /*
        * phoneNumber := phoneNumber - phoneNumber[index]
        */
        phoneNumber.remove(index);
    }
    public void rmAddress(int index)
    {
        /*
        * address := address - address[index]
        */
        address.remove(index);
    }
    public void rmEmail(int index)
    {
        /*
        * email := email - email[index]
        */
        email.remove(index);
    }
    public void rmIM(int index)
    {
        /*
        * im := im - im[index]
        */
        im.remove(index);
    }

    //getters
    public NameObject getName(int getName)
    {
        /*
        * if getName < number of NameObjects in the contact->
        *      return NameObject located at name[getName]
        * else->
        *      return null
        */
        if(getName < name.size())
        {
            return(name.get(getName));
        }
        else
        {
            return(null);
        }
    }
    public PhoneObject getPhoneNumber(int getPhone)
    {
        /*
        * if getPhone < number of PhoneObjects in the contact->
        *      return PhoneObject located at phoneNumber[getPhone]
        * else->
        *      return null
        */
        if(getPhone < phoneNumber.size())
        {
            return(phoneNumber.get(getPhone));
        }
        else
        {
            return(null);
        }
    }
    public AddressObject getAddress(int getAddress)
    {
        /*
        * if getAddress < number of AddressObjects in the contact->
        *      return AddressObject located at address[getAddress]
        * else->
        *      return null
        */
        if(getAddress < address.size())
        {
            return(address.get(getAddress));
        }
        else
        {
            return(null);
        }
    }
    public EmailObject getEmail(int getEmail)
    {
        /*
        * if getEmail < number of EmailObjects in the contact->
        *      return EmailObject located at email[getEmail]
        * else->
        *      return null
        */
        if(getEmail < email.size())
        {
            return(email.get(getEmail));
        }
        else
        {
            return(null);
        }
    }
    public IMObject getIM(int getIM)
    {
        /*
        * if getIM < number of IMObjects in the contact->
        *      return IMObject located at im[getIM]
        * else->
        *      return null
        */
        if(getIM < im.size())
        {
            return(im.get(getIM));
        }
        else
        {
            return(null);
        }
    }

    public ArrayList<NameObject> getNameList()
    {
        /*
        * return the name ArrayList
        */
        return name;
    }

    public ArrayList<PhoneObject> getPhoneNumberList()
    {
        /*
        * return the phoneNumber ArrayList
        */
        return phoneNumber;
    }

    public ArrayList<AddressObject> getAddressList()
    {
        /*
        * return the address ArrayList
        */
        return address;
    }

    public ArrayList<EmailObject> getEmailList()
    {
        /*
        * return the email ArrayList
        */
        return email;
    }

    public ArrayList<IMObject> getIMList()
    {
        /*
        * return the im ArrayList
        */
        return im;
    }
}


public class ContactManager 
{
    /*
    * 
    */
    public static void main(String[] args) 
    {
        /*
        * stdin +:= 
        *      User input to drive menu operations
        * stdout +:=
        *      UI output to provide user feedback and menu support
        * stderr +:= 
        *      Desription of encountered error(s) along with Java JVM error
        *      report of the internal issue which caused the error
        * [file chosen by user] :+= 
        *      Encrypted XML document containing contact list saved by the user
        * 
        */
        //Define operating variables:
        ArrayList<ContactObject> contactCollection = new ArrayList();
        
        //Load all contacts from default file on startup
        
        
        //Display user interface
        viewInterface(contactCollection);
        
        //Exit application:
        System.exit(0);
        
    }
    private static void printMenu()
    {
        /*
        * stdout +:= 
        *      The main menu of the application (as shown below in 
        *      System.out.println())
        */
        //Print the main menu for the application:
        System.out.println("Please select from the following options:\n"
        + "1. Print contact list\n"
        + "2. Search for a contact\n"
        + "3. Add a new contact\n"
        + "4. Remove an existing contact\n"
        + "5. Edit an existing contact\n"
        + "6. Load a contact list\n"
        + "7. Export contacts to a list\n"
        + "8. Exit");
    }
    private static void printAllContacts(ArrayList<ContactObject> contactCollection)
    {
        /*
        * stdout +:=
        *      each contact in contactCollection 
        */
        
        //View all contacts
        int i = 0;
        /*
        * At completion:
        *      i = number of contacts in contactCollection
        *      stdout +:= 
        *          all contacts with all info about them printed
        */
        while(i < contactCollection.size())
        {
            /*
            * stdout +:=
            *      All contact information held in the contact entry of the 
            *      contact at position contactCollection[i]
            */
            printContact(contactCollection.get(i));
            System.out.println("");
            i++;
        }
    }
    private static void handleMenuChoice(int menuChoice,ArrayList<ContactObject> contactCollection, BufferedReader br)
    {    
        /*
        * stdout +:=
        * if menuChoice = 1 ->
        *      stdout +:= 
        *          All information about each contact contained in 
        *          contactCollection is printed out 
        * else if menuChoice = 2 ->
        *      stdin +:= 
        *          Prefix of first, middle, sir or nick name provided by the 
        *          user.
        *      stdout +:=
        *          All contact infrormation for each contact that match the 
        *          search query in first, middle, sir or nick name. 
        *      stderr +:=
        *          Errors with parsing the string provided by the user for 
        *          searching
        * else if menuChoice = 3 ->
        *      stdout +:=
        *          Menu prompts for each attribute of a contact
        *      stdin +:= 
        *          Field information for each attribute to be assigned to the 
        *          contact
        *      stderr +:=
        *          Errors with parsing or accessing strings provided by the user
        *          for fields
        * else if menuChoice = 4 ->
        *      stdout +:=
        *          List of all contacts with numbers next to each
        *      stdin +:=
        *          Number of the contact to remove
        *      stderr +:=
        *          Errors with parsing or accessing choice provided by the 
        *          user for deletion.
        * else if menuChoice = 5 ->
        *      stdout +:=
        *          List of all contacts with numbers next to each
        *          List of each attribute that could be edited
        *          Prompts for each field during editing process
        *      stdin +:=
        *          Field information for each attribute to be assigned to the 
        *          contact
        *      stderr +:=
        *          Errors with parsing or accessing strings provided by the 
        *          user for fields.
        * else if menuChoice = 6 ->
        *      stdout +:=
        *          Prompt for the relative file location to load from
        *      stdin +:= 
        *          Relative file path
        *      stderr +:=
        *          Error messages for failures during accessing string provided
        *          for file path.
        *          Error messages for failures during file decryption
        * else if menuChoice = 7 ->
        *      stdout +:=
        *          Prompt for relative file path to export to
        *          Prompt for password to be used during file encryption
        *      [file] +:=
        *          DES encrypted XML file of contacts
        *      stdin +:=
        *          Relative path for export file
        *          Password for file encryption
        *      stderr +:=
        *          Error messages for failures during accessing string provided
        *          for file path and passsword.
        *          Error messages for failures during file encryption
        * else if menuChoice == 8  ->
        *      stdin +:=
        *          Advanced to EOF when buffer closes
        *      stderr +:=
        *          Any error messages provided during stdin buffered reader close
        * else
        *      stdout +:=
        *          Prompt for valid input
        */
        if(menuChoice == 1)
        {
            printAllContacts(contactCollection);
        }
        else if(menuChoice == 2)
        {
            //Search for a contact
            findContact(contactCollection, br);
        }
        else if(menuChoice == 3)
        {
            //Add a new contact
            addContact(contactCollection, br);
        }
        else if(menuChoice == 4)
        {
            //Remove a contact
            int chosenContact = chooseContact(contactCollection, br);
            removeContact(chosenContact, contactCollection);
        }
        else if(menuChoice == 5)
        {
            //Edit a contact
            int chosenContact = chooseContact(contactCollection, br);
            editContact(contactCollection.get(chosenContact), br);
        }
        else if(menuChoice == 6)
        {
            //Load a contact list
            openFile(contactCollection, br);

        }
        else if(menuChoice == 7)
        {
            //Export contacts
            writeContacts(contactCollection, br);
        }
        else if(menuChoice == 8)
        {
            //Exit
            try
            {
                br.close();
            }
            catch(Exception e)
            {
                System.err.println("Error processing input/closing stdin reader: " + e.getMessage());
            }
        }
        else
        {
            //Undefined input
            System.out.println("Unrecognized input, please try again");
        }
    }
    private static void viewInterface(ArrayList<ContactObject> contactCollection)
    {
        int menuChoice = 0;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        /*
        * System.out +:= Output messages given from the results of the user's menu choices
        * 
        */
        //Stay in menu until exit:
        while(menuChoice != 8)
        {
            try
            {
                printMenu();

                menuChoice = Integer.parseInt(br.readLine());
                
                handleMenuChoice(menuChoice,contactCollection,br);
                
            }//end Try
            catch(Exception e)
            {
                System.err.println("Error processing input/closing stdin reader." + e.getMessage());
            }
        } 
    }


    private static int chooseContact(ArrayList<ContactObject> contactCollection, BufferedReader br)
    {
        /*
        * 
        */
        //Choose a contact
        int returnContactNumber = -1;
        
        /*
        * if (contactCollection is empty) ->
        *   System.out +:= "No contacts are in the collection"
        *   return -1
        * else ->
        *   System.out +:= (contact number) + ". \n" + (contact details) for every ContactObject within contactCollection
        *   System.out +:= "Please enter the number of the contact to edit:"
        *   br := br advanced to EOF
        *   if (successfully parsed Integer from the command line) ->
        *       returnContactNumber := (an integer)
        *   else ->
        *       System.err +:= "The program has encountered an error in "
        *                + "parsing the contact number. Java error message:\n" 
        *                + (JVM error message)
        *   return returnContactNumber
        */
        if(contactCollection.isEmpty())
        {
            /*
            *   [ System.out +:= "No contacts are in the collection"
            *   return -1 ]
            */
            //no contacts to print, exit the printing after a message to user
            System.out.println("No contacts are in the collection");
            return(returnContactNumber);
        }
        /*
        *   [ System.out +:= (contact id number) + ". \n" + (contact details) for every ContactObject within contactCollection
        *   System.out +:= "Please enter the number of the contact to edit:"
        *   br := br advanced to EOF
        *   if (successfully parsed Integer from the command line) ->
        *       returnContactNumber := (an integer)
        *   else ->
        *       System.err +:= "The program has encountered an error in "
        *                + "parsing the contact number. Java error message:\n" 
        *                + (JVM error message)
        *   return returnContactNumber ]
        */
        else
        {
            /*
            * [ System.out +:= (contact id number) + ". \n" + (contact details) for every ContactObject within contactCollection ]
            */
            for(int i = 0; i < contactCollection.size(); i++)
            {
                //print out all contacts in the collection
                System.out.println(i +". ");
                printContact(contactCollection.get(i));
            }
            
            /*
            * System.out +:= "Please enter the number of the contact to edit:"
            * br := br advanced to EOF
            */
            System.out.println("Please enter the number of the contact to edit:");
            
            /*
            *   [ if (successfully parsed Integer from the command line) ->
            *       returnContactNumber := (an integer) ]
            */
            try
            {
                returnContactNumber = Integer.parseInt(br.readLine());
            }
            /*
            * else ->
            *   System.err +:= "The program has encountered an error in "
            *              + "parsing the contact number. Java error message:\n" 
            *              + (JVM error message)
            */
            catch(Exception e)
            {
                //problem with reading line and converting to integer
                System.err.println("The program has encountered an error in "
                + "parsing the contact number. Java error message:\n" 
                + e);
            }
            //return the contact number that was provided by the user
            return(returnContactNumber);
        }
    }
    
    /*
    * [ System.out +:= (contact details) for every NameObject stored in contact that contains searchName ]
    */
    private static void searchContactNames(ContactObject contact,String searchName)
    {
        NameObject cName;
        
        /*
        * [ System.out +:= (contact details for the currect contact) for each NameObject that contains searchName 
        *   cName := (last NameObject in contact) ]
        *   sString := cName.firstName + cName.middleName + cName.sirName + cName.nickName ]
        */
        // Go through each name
        for (int j = 0; j < contact.getNameList().size(); j++)
        {
            /*
            * cName := (current NameObject in contact)
            * sString := cName.firstName + cName.middleName + cName.sirName + cName.nickName
            */
            
            // Get the name
            cName = contact.getName(j);
            
            // Build a string contain every part of the name
            String sString = cName.firstName + cName.middleName + cName.sirName + cName.nickName;
            
            /*
            * [ if (searchName was found in sString) ->
            *   System.out +:= (contact details for the currect contact)
            * else ->
            *   I ]
            */
            // Search the built string for what we want
            if (sString.toLowerCase().indexOf(searchName.toLowerCase()) != -1)
            {
                /*
                * [ System.out +:= (contact details for the currect contact) ]
                */
                printContact(contact);
            }
        }
    }
    
    /*
    * [ System.out +:= "Please enter a name of the contact (first, middle, last or nick)"
    *   if (searched the contactCollection without error) ->
    *       System.out +:= (contact details) for the contact containing the name to find
    *       br := br advanced to EOF
    *   else ->
    *       System.err +:= "Error parsing name string for searching: " + (error message) ]
    */
    private static void findContact(ArrayList<ContactObject> contactCollection, BufferedReader br)
    {
        /*
        * [ System.out +:= "Please enter a name of the contact (first, middle, last or nick)"
        *   if (searched the contactCollection without error) ->
        *       System.out +:= (contact details) for the contact containing the name to find
        *       br := br advanced to EOF ]
        */
        try
        {
            System.out.println("Please enter a name of the contact (first, middle, last or nick)");
            String searchName = br.readLine();

            ContactObject curContact;

            /*
            */
            // Go through each contact
            for(int i=0; i < contactCollection.size(); i++)
            {
                curContact = contactCollection.get(i);
                searchContactNames(curContact,searchName);
            }
        }
        catch(Exception e)
        {
            //Error in searchig through contact list using provided search string
            System.err.println("Error parsing name string for searching: " + e.getMessage());
        }
    }
    
    private static void makeAddName(BufferedReader br, ContactObject newContact)
    throws Exception
    {
        /*
        * stdout +:= 
        *      Prompts for First, Middle, Sir, and Nick name, as well as a 
        *      check for primary 
        * stdin +:=
        *      A string cooresponding to each field in the NameObject
        */
        //----NAME
        //declarations needed for Name:
        NameObject name = new NameObject();
        
        System.out.println("Name Section:\n First name:");
        name.firstName = br.readLine();
        
        System.out.println("Middle name:");
        name.middleName = br.readLine();
        
        System.out.println("Sir name:");
        name.sirName = br.readLine();
        
        System.out.println("Nick name:");
        name.nickName = br.readLine();
        
        name.primaryName = primaryCheck(br);
        newContact.addName(name);
    }
    
    private static void makeAddPhone(BufferedReader br, ContactObject newContact)
    throws Exception
    {
        /*
        * stdout +:= 
        *      Prompts for area code and local phone number, as well as a check
        *      for primary
        * stdin +:=
        *      A string cooresponding to each field in the PhoneObject
        */
        
        PhoneObject phone = new PhoneObject();
        
        System.out.println("Phone Section:\n Area Code:");
        phone.areaCode = br.readLine();
        
        System.out.println("Local Number:");
        phone.localNumber = br.readLine();
        
        phone.primaryPhone = primaryCheck(br);
        newContact.addPhoneNumber(phone);
    }
    
    private static void makeAddAddress(BufferedReader br, ContactObject newContact)
    throws Exception
    {
        /*
        * stdout +:= 
        *      Prompts for State, City, Zip Code, and Street Address, as 
        *      well as a check for primary
        * stdin +:=
        *      A string cooresponding to each field in the AddressObject
        */
        AddressObject address = new AddressObject();
        
        System.out.println("Address Section:\n State:");
        address.state = br.readLine();
        
        System.out.println("City:");
        address.city = br.readLine();
        
        System.out.println("Zip Code:");
        address.zipCode = br.readLine();
        
        System.out.println("Street Address:");
        address.streetAddress = br.readLine();
        
        address.primaryAddress = primaryCheck(br);
        
        newContact.addAddress(address);
    }
    
    private static void makeAddEmail(BufferedReader br,ContactObject newContact)
    throws Exception
    {
        /*
        * stdout +:= 
        *      Prompt for Email address and primary check
        * stdin +:=
        *      A string cooresponding to each field in the EmailObject
        */
        EmailObject email = new EmailObject();
        
        System.out.println("Email Address Section:\n Email Address:");
        email.emailAddress = br.readLine();
        
        email.primaryEmail = primaryCheck(br);
        
        newContact.addEmail(email);
    }
    
    private static void madeAddIM(BufferedReader br,ContactObject newContact)
    throws Exception
    {
        /*
        * stdout +:= 
        *      Prompts for IM provider and username, as well as a primary check
        * stdin +:=
        *      A string cooresponding to each field in the IMObject
        */
        IMObject im = new IMObject();
        
        System.out.println("IM Address Section:\n IM Provider:");
        im.provider = br.readLine();
        
        System.out.println("IM User Name:");
        im.userName = br.readLine();
        
        im.primaryIM = primaryCheck(br);
        
        newContact.addIM(im);
    }
    
    private static void addContact(ArrayList<ContactObject> contactCollection, BufferedReader br)
    {
        /*
        * [ contactCollection := (contactCollection with newContact added)
        *   br := br advanced to EOF
        *   System.out +:= (messages asking for all of a new contact's information) or (error message)
        * ]
        */
        //Add a new contact to the current list
        ContactObject newContact = new ContactObject();
        
        /*
        * if (successfully added newContact) ->
        *   newContact := (newContact with name, phone, email, im, and birthday added)
        *   contactCollection := (contactCollection with newContact added)
        *   System.out +:= (messages asking for all of a new contact's information)
        * else ->
        *   System.err +:= (error message)
        */
        
        try
        {            
            /*
            * [ newContact.name := (NameObject created from br)
            *   br := br advanced to EOF
            *   System.out +:= (messages asking for all of a new contact's information) ]
            */
            //----NAME
            makeAddName(br,newContact);
            
            /*
            * [ newContact.phone := (PhoneObject created from br)
            *   br := br advanced to EOF
            *   System.out +:= (message asking for the phone number) ]
            */
            //----PHONE
            makeAddPhone(br,newContact);
            
            /*
            * [ newContact.address := (AddressObject created from br)
            *   br := br advanced to EOF
            *   System.out +:= (message asking for the address) ]
            */
            //----Address
            makeAddAddress(br,newContact);
            
            /*
            * [ newContact.email := (EmailObject created from br)
            *   br := br advanced to EOF
            *   System.out +:= (message asking for the email address) ]
            */
            //----Email
            makeAddEmail(br,newContact);
            
            /*
            * [ newContact.IM := (IMObject created from br)
            *   br := br advanced to EOF
            *   System.out +:= (message asking for the IM provider and IM name) ]
            */
            //----IM
            madeAddIM(br,newContact);
            
            /*
            * [ System.out +:= "Please enter the contact's birthday: "
            *   newContact.Birthday := (birthday)
            *   br := br advanced to EOF]
            */
            //----Birthday
            System.out.println("Please enter the contact's birthday: ");
            String birthday = br.readLine();
            newContact.setBirthday(birthday);
            
            /*
            * [ contactCollection := (contactCollection with newContact added) ]
            */
            //add the contact
            contactCollection.add(newContact);
        }//end Try
        catch(Exception e)
        {
            //problem with reading line and converting to integer
            System.err.println("The program has encountered an error in "
            + "parsing the contact number. Java error message:\n" 
            + e);
        }
    }
    
    private static boolean removeContact(int chosenContact, 
    ArrayList<ContactObject> contactCollection)
    {
        /*
        * if (chosenContact exists in contactCollection) ->
        *  contactCollection := (contactCollection with chosenContact removed) 
        * else
        *  System.err +:= "The supplied contact number is invalid.\n"
        */
        //Remove a contact from the current list
        if(contactCollection.size() <= chosenContact && chosenContact >= 0)
        {
            //The range supplied indicates a valid choice for deletion, preform operation
            contactCollection.remove(chosenContact);
            return(true);
        }
        else
        {
            System.err.println("The supplied contact number is invalid.");
            return(false);
        }
    }
    
    private static void printNameInfo(ContactObject contact)
    {
        /* 
        * [ System.out +:= "Name:\n" + 
        *      ("\t" + (first name) + " " + (middle name) + " " + (last name)
        *        + " (" + (nick name) + ")\n"
        *        for every NameObject contained within contact) ]
        */
        NameObject printName;
        
        System.out.println("Name:");
        /*
        * [ System.out +:= "\t" + (first name) + " " + (middle name)
            + " " + (last name) + + " (" + (nick name) + ")\n" for every NameObject in contact
        *   printName := (last listed NameObject in contact) ]
        */
        for(int i = 0; i < contact.getNameList().size(); i++)
        {
            printName = contact.getName(i);
            System.out.println("\t"+printName.firstName+" "+printName.middleName+" "+printName.sirName+" ("+printName.nickName+")");
        }
    }
    
    private static void printPhoneInfo(ContactObject contact)
    {
        /* 
        * [ System.out +:= "Phone number:\n" + 
        *      ("\t" + (area code) + "-" + (local number) + "\n"
        *        for every PhoneObject contained in contact) ]
        */
        PhoneObject printPhone;
        
        System.out.println("Phone number:");
        /*
        * [ System.out +:= "\t" + (area code) + "-" + (local number) + "\n" for every PhoneObject in contact
        *   printPhone := (last listed PhoneObject in contact) ]
        */
        for(int i = 0; i < contact.getPhoneNumberList().size(); i++)
        {
            printPhone = contact.getPhoneNumber(i);
            //Print phone
            System.out.println("\t"+printPhone.areaCode+"-"+printPhone.localNumber);
        }
    }
    
    private static void printAddressInfo(ContactObject contact)
    {
        /* 
        * [ System.out +:= "Address:\n" + 
        *      ("\t" + (street address) + (city) + " " + (state) + " " + (zip code) + "\n"
        *        for each AddressObject contained within contact) ]
        */
        AddressObject printAddress;
        
        System.out.println("Address:");
        /*
        * [ System.out +:= ("\t" + (street address) + (city) + " " + (state) + " " + (zip code) + "\n") for each AddressObject contained with contact
        *   printAddress := (last listed AddressObject in contact) ]
        */
        for(int i = 0; i < contact.getAddressList().size(); i++)
        {
            printAddress = contact.getAddress(i);
            //Print Address
            System.out.println("\t"+printAddress.streetAddress+"\n\t"+printAddress.city+" "+printAddress.state+" "+printAddress.zipCode);
        }
    }
    
    private static void printEmailInfo(ContactObject contact)
    {
        /* [ System.out +:= "Email Address:\n" + 
                ("\t" + (email address) + "\n"
                for each email address contained within contact) ]
        */
        
        EmailObject printEmail;
        
        System.out.println("Email Address:");
        /*
        * [ System.out +:= "\t" + (email address) + "\n" for every EmailObject in contact ]
        *   printEmail := (last listed email address in contact) 
        */
        for(int i = 0; i < contact.getEmailList().size(); i++)
        {
            printEmail = contact.getEmail(i);
            //Print Email
            System.out.println("\t"+printEmail.emailAddress);
        }
    }
    
    private static void printIMInfo(ContactObject contact)
    {
        /*
        * [ System.out +:= "IM:\n" + 
        *      ("\t" + (IM provider) + " - " + (IM username) + "\n"
        *        for each IMObject contained within contact) ]
        */
        
        IMObject printIM;
        
        System.out.println("IM:");
        /*
        * [ System.out +:= "\t" + (IM provider) + " - " + (IM username) + "\n" for every IMObject in contact
        *   printIM := (last listed IM address in contact) ]
        */
        for(int i = 0; i < contact.getIMList().size(); i++)
        {
            printIM = contact.getIM(i);
            //Print IM
            System.out.println("\t"+printIM.provider+" - "+printIM.userName);
        }
    }
    
    private static void printContact(ContactObject contact)
    {
        /*
        * 
        *
        */
        //Print out all of the credentials for a single contact        
        printNameInfo(contact);
        
        printPhoneInfo(contact);
        
        printAddressInfo(contact);
        
        printEmailInfo(contact);
        
        printIMInfo(contact);
    }
    
    private static boolean primaryCheck(BufferedReader br)
    {
        /*
        * Try ->
        *      primaryFilled := false //Details if the primary attribute has 
        *                               been chosen by the user (yes or no)
        *      primaryYN := false     //Details if this attribute is a primary
        *                               yes = true, no = false
        * 
        *      if primaryCheck = 'y' ->
        *          primaryYN = true
        *          primaryFilled = true
        *      else if primaryCheck = 'n' ->
        *          primaryYN = false
        *          primaryFilled = true
        *      else ->
        *          stdout +:= Request the user to retry the check for primary
        * Catch ->
        *      stderr +:= Error detailing that the input was not understood
        */
        //Check with the user to determine if a set of attributes should be used as a primary
        try
        {
            boolean primaryFilled = false;
            boolean primaryYN = false;
            while(primaryFilled != true)
            {
                System.out.println("Is this a primary attribute for this "
                + "contact (y/n)?");
                String primaryCheck = br.readLine();
                if(primaryCheck.equals("y"))
                {
                    primaryYN = true;
                    primaryFilled = true;
                }
                else if(primaryCheck.equals("n"))
                {
                    primaryYN = false;
                    primaryFilled = true;
                }
                else
                {
                    //Misunderstood input, prompt again
                    System.out.println("Impropper answer provided, please try "
                    + "again.");
                }
            }
            return(primaryYN);
        }
        catch(Exception e)
        {
            //some error occured getting user input
            System.err.println("An error has occured when checking for primary attribute: " +e.getMessage());
            return(false);
        }
    }
    
    private static boolean deleteCheck(BufferedReader br)
    {
        /*
        * 
        */
        //Check with the user to determine if a set of attributes should be used as a primary
        try
        {
            boolean deleteFilled = false;
            boolean deleteYN = false;
            while(deleteFilled != true)
            {
                System.out.println("Delete this attribute from the "
                + "contact (y/n)?");
                String primaryCheck = br.readLine();
                if(primaryCheck.equals("y"))
                {
                    deleteYN = true;
                    deleteFilled = true;
                }
                else if(primaryCheck.equals("n"))
                {
                    deleteYN = false;
                    deleteFilled = true;
                }
                else
                {
                    //Misunderstood input, prompt again
                    System.out.println("Improper answer provided, please try "
                    + "again.");
                }
            }
            return(deleteYN);
        }
        catch(Exception e)
        {
            //some error occured getting user input
            System.err.println("An error has occured when checking for deletion of contact/attribute: " +e.getMessage());
            return(false);
        }
    }
    
    private static void editContact(ContactObject contact, BufferedReader br)
    {
        /*
        * 
        */
        //Edit a field for an existing contact
        
        try
        {
            System.out.println("Choose an attribute would you like to edit:\n"
            + "1. Name\n"
            + "2. Phone\n"
            + "3. Address\n"
            + "4. Email\n"
            + "5. Instant Messenger\n"
            + "6. Birthday\n");
            int selection = Integer.parseInt(br.readLine());
            
            //iterator through whiles for names
            int i = 0;
            
            if(selection == 1)
            {
                //Edit name attribute of contact
                NameObject editedName = new NameObject();
                
                //get the number of the instance of name to edit
                while(contact.getName(i) != null)
                {
                    System.out.println(i +". " + contact.getName(i).firstName +
                    " " + contact.getName(i).middleName + " " +
                    contact.getName(i).sirName + " " +
                    contact.getName(i).nickName);
                    i++;
                }
                
                System.out.println("Please enter the number of the attribute to edit: ");
                int subSelection = Integer.parseInt(br.readLine());
                
                if(deleteCheck(br))
                {
                    //Delete this attribute completly
                    contact.rmName(subSelection);
                }
                else
                {
                    System.out.println("Enter new value for First Name: ");
                    String newFirstName = br.readLine();

                    System.out.println("Enter new value for Middle Name: ");
                    String newMiddleName = br.readLine();

                    System.out.println("Enter new value for Sir Name: ");
                    String newSirName = br.readLine();

                    System.out.println("Enter new value for Nick Name: ");
                    String newNickName = br.readLine();

                    editedName.primaryName = primaryCheck(br);

                    //Set new values
                    editedName.firstName = newFirstName;
                    editedName.middleName = newMiddleName;
                    editedName.sirName = newSirName;
                    editedName.nickName = newNickName;
                    
                    contact.addName(editedName);
                }
                
            }
            else if(selection == 2)
            {
                PhoneObject editedPhone = new PhoneObject();
                
                while(contact.getPhoneNumber(i) != null)
                {
                    System.out.println(i +". " + contact.getPhoneNumber(i).areaCode 
                    + " " + contact.getPhoneNumber(i).localNumber);
                    i++;
                }
                System.out.println("Please enter the number of the attribute to edit: ");
                int subSelection = Integer.parseInt(br.readLine());
                
                if(deleteCheck(br))
                {
                    //Delete this attribute completly
                    contact.rmPhoneNumber(subSelection);
                }
                else
                {
                    System.out.println("Enter new value for Area Code: ");
                    String newAreaCode = br.readLine();

                    System.out.println("Enter new value for Local Number: ");
                    String newLocalNumber = br.readLine();

                    editedPhone.primaryPhone = primaryCheck(br);

                    //Set new values:
                    editedPhone.areaCode = newAreaCode;
                    editedPhone.localNumber = newLocalNumber;

                    contact.addPhoneNumber(editedPhone);
                }
                
            }
            else if(selection == 3)
            {
                AddressObject editedAddress = new AddressObject();
                
                while(contact.getAddress(i) != null)
                {
                    System.out.println(i +". " + contact.getAddress(i).state +" "
                    + contact.getAddress(i).city + " " +
                    contact.getAddress(i).streetAddress + " " +
                    contact.getAddress(i).zipCode);
                    i++;
                }
                System.out.println("Please enter the number of the attribute to edit: ");
                int subSelection = Integer.parseInt(br.readLine());
                
                if(deleteCheck(br))
                {
                    //Delete this attribute completly
                    contact.rmAddress(subSelection);
                }
                else
                {
                    System.out.println("Enter new value for State: ");
                    String newState = br.readLine();

                    System.out.println("Enter new value for City: ");
                    String newCity = br.readLine();

                    System.out.println("Enter new value for Zip Code: ");
                    String newZipCode = br.readLine();

                    System.out.println("Enter new value for Street Address: ");
                    String newStreetAddress = br.readLine();

                    editedAddress.primaryAddress = primaryCheck(br);

                    //Set new values:
                    editedAddress.state = newState;
                    editedAddress.city = newCity;
                    editedAddress.zipCode = newZipCode;
                    editedAddress.streetAddress = newStreetAddress;

                    contact.addAddress(editedAddress);
                }
            }
            else if(selection == 4)
            {
                EmailObject editedEmail = new EmailObject();
                
                while(contact.getEmail(i) != null)
                {
                    System.out.println(i +". " + contact.getEmail(i).emailAddress);
                    i++;
                }
                System.out.println("Please enter the number of the attribute to edit: ");
                int subSelection = Integer.parseInt(br.readLine());
                
                if(deleteCheck(br))
                {
                    //Delete this attribute completly
                    contact.rmEmail(subSelection);
                }
                else
                {
                    System.out.println("Enter new value for Email Address: ");
                    String newEmailAddress = br.readLine();

                    editedEmail.primaryEmail = primaryCheck(br);

                    //Set new values:
                    editedEmail.emailAddress = newEmailAddress;

                    contact.addEmail(editedEmail);
                }
            }
            else if(selection == 5)
            {
                IMObject editedIM = new IMObject();
                
                while(contact.getIM(i) != null)
                {
                    System.out.println(i +". " + contact.getIM(i).provider +" " +
                    contact.getIM(i).userName);
                    i++;
                }
                System.out.println("Please enter the number of the attribute to edit: ");
                int subSelection = Integer.parseInt(br.readLine());
                
                if(deleteCheck(br))
                {
                    //Delete this attribute completly
                    contact.rmIM(subSelection);
                }
                else
                {
                    System.out.println("Enter new value for IM Provider: ");
                    String newProvider = br.readLine();

                    System.out.println("Enter new value for IM Username: ");
                    String newUserName = br.readLine();

                    editedIM.primaryIM = primaryCheck(br);

                    //Set new values:
                    editedIM.provider = newProvider;
                    editedIM.userName = newUserName;

                    contact.addIM(editedIM);
                }
            }
            else if(selection == 5)
            {
                String birthday;
                
                System.out.println("Current birthday: " + contact.getBirthday());
                
                System.out.println("Please enter the new value for birthday: ");
                String newBirthday = br.readLine();
                
                contact.setBirthday(newBirthday);
            }
        }
        catch(Exception e)
        {
            //There was an error parsing the user input
            System.err.println("Error parsing user selection. Java report: " +
            e.getMessage());
        }
        
    }
    
    private static void openFile(ArrayList<ContactObject> contactCollection, BufferedReader br)
    {
        /*
        * 
        */
        //Open a file of contacts and add them to the current list
        try
        {
            System.out.println("Please enter the name/relative path of the file to open:");
            String fileName = br.readLine();
            
            
            File file = new File(fileName);
            
            if(file.exists())
            {
                System.out.println("Please enter the password for the file to be opened:");
                String passwordString = br.readLine();

                ContactXMLParser parser = new ContactXMLParser(fileName);
                parser.ImportContacts(contactCollection, passwordString);
            }
            else
            {
                //The path provided does not point to an existing file
                System.out.println("The provided path does not point to a valid file.");
            }
        }
        catch(Exception e)
        {
            //problem opening file
            System.err.println("Error opening file: " + e.getMessage());
        }
    }

    private static void writeContacts(ArrayList<ContactObject> contactCollection, BufferedReader br)
    {
        /*
        * 
        */
        //Write a single contact to an output file
        try
        {
            System.out.println("Please enter the name/relative path of the file to open:");
            String fileName = br.readLine();

            System.out.println("Please enter the password to encrypt the contacts file:");
            String passwordString = br.readLine();

            ContactXMLWriter writer = new ContactXMLWriter(fileName);
            writer.ExportContacts(contactCollection, passwordString);
        }
        catch(Exception e)
        {
            //An error in writing the encrypted file has occured
            System.err.println("An error in writing the encrypted file has occured: " + e.getMessage());
        }
    }
}
